#ifndef TREE_NODE_H
#define TREE_NODE_H
#include <string.h>
#include <vector>
#include "tiny-parser.tab.h"

using namespace std;

extern int lineno ;

enum NodeKind{StmtK=1,ExpK} ;
enum StmtKind{Stmt_K=3,IfK,RepeatK,AssignK,ReadK,WriteK} ;
enum ExpKind {OpK=9,ConstK,IdK} ;
/* ExpType is used for type checking */
enum ExpType{Void_type=9,Integer,Boolean} ;


#define Token_Kind int

class TreeNode{
private:
    void show_info(int depth,bool is_last_child);
public:
    NodeKind kind;
    int lineno;
    union { StmtKind stmt; ExpKind exp;} production_kind;
    union { Token_Kind op;
            int val;   
            char *name; } attr;
    ExpType type; /* for type checking of exps */
    vector<TreeNode *> children;


    void copy_name(const char *name){
        this->attr.name=new char(strlen(name));
        strcpy(this->attr.name,name);
    };
    void show_all_info();


    TreeNode(int line){
        this->lineno = line;
    }

    template<typename... Args>
    TreeNode(int line,TreeNode * first_child, Args... args){
        this->lineno = line;
        this->children.push_back(first_child);
        (this->children.push_back(args),...);
    };
    ~TreeNode(){
        if(this->production_kind.exp==IdK){
            delete this->attr.name;
        }
    }

    virtual void generate_code()=0;
};


TreeNode * new_stmt_node();

TreeNode * new_if_stmt(int line,TreeNode * cond, TreeNode * then_stmt, TreeNode * else_stmt);
TreeNode * new_if_stmt(int line,TreeNode * cond, TreeNode * then_stmt);

TreeNode * new_repeat_stmt(int line, TreeNode * body,TreeNode * cond);

TreeNode * new_assign_stmt(int line,TreeNode * var, TreeNode * exp);

TreeNode * new_read_stmt(int line,TreeNode * var);

TreeNode * new_write_stmt(int line,TreeNode * exp);

TreeNode * new_exp(int line,TreeNode * left, Token_Kind op, TreeNode * right);
TreeNode * new_exp(int line,TreeNode * simple_exp);

TreeNode* new_simple_exp(int line,TreeNode * left, Token_Kind op, TreeNode * right);

TreeNode * new_term(int line,TreeNode * left, Token_Kind op, TreeNode * right);
TreeNode * new_term(int line,TreeNode * factor);


TreeNode * new_num(int line,int val);
TreeNode * new_id(int line,const char *name);

#endif